//-----------------------------------------------------------------------
// <copyright file="IMAddressPresence.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Microsoft.Live.Messenger
{
    using System;
    using System.ComponentModel;
    using Microsoft.Live.Core;

    /// <summary>
    /// Represents presence information associated with an instant messaging address, such as status, IM address, display name, display picture URL, and so on.
    /// </summary>
    public sealed class IMAddressPresence : INotifyPropertyChanged
    {
        private readonly MessengerEntity entity;
        private readonly IMAddress address;

        private PresencePropertyCollection properties;

        internal IMAddressPresence(object obj, IMAddress address)
        {
            this.entity = new MessengerEntity(obj);
            this.entity.AttachEvent("PropertyChanged", this.OnPropertyChanged);

            this.address = address;
        }

        /// <summary>
        /// Gets the associated instant messaging address.
        /// </summary>
        public IMAddress IMAddress
        {
            get { return this.address; }
        }

        /// <summary>
        /// Gets the properties associated with the address.
        /// </summary>
        public PresencePropertyCollection Properties
        {
            get
            {
                if (this.properties == null)
                {
                    this.properties = new PresencePropertyCollection(this.entity.GetProperty("Properties"));
                }
                return this.properties;
            }
        }

        /// <summary>
        /// Gets the display name for the instant messaging address.
        /// </summary>
        public string DisplayName
        {
            get { return this.entity.GetProperty<string>("DisplayName"); }

            set
            {
                this.EnsureUser();

                if (!this.address.User.Settings.CanUpdateDisplayName)
                {
                    throw new InvalidOperationException();
                }

                if (!IsDisplayNameValid(value))
                {
                    throw new ArgumentOutOfRangeException();
                }                
                
                this.entity.SetProperty<string>("DisplayName", value);
            }
        }

        /// <summary>
        /// Gets the display picture URL for the instant messaging address.
        /// </summary>
        public Uri DisplayPictureUrl
        {
            get { return this.entity.GetUriProperty("DisplayPictureUrl"); }
        }

        /// <summary>
        /// Gets the personal message for the instant messaging address.
        /// </summary>
        public string PersonalMessage
        {
            get { return this.entity.GetProperty<string>("PersonalMessage"); }
            set
            {
                this.EnsureUser();

                if (!IsPersonalMessageValid(value))
                {
                    throw new ArgumentOutOfRangeException();
                }
                
                this.entity.SetProperty<string>("PersonalMessage", value); }
        }

        /// <summary>
        /// Gets the status for the instant messaging address.
        /// </summary>
        public PresenceStatus Status
        {
            get { return this.entity.GetEnumProperty<PresenceStatus>("Status"); }

            set
            {
                if (!Enum.IsDefined(typeof(PresenceStatus), value))
                {
                    throw new ArgumentOutOfRangeException();
                }

                this.entity.SetProperty<PresenceStatus>("Status", value);
            }
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        /// <summary>
        /// Determines whether the provided display name is valid.
        /// </summary>
        /// <param name="displayName">The display name to validate.</param>
        /// <returns><c>true</c> if the display name is valid; <c>false</c> otherwise.</returns>
        public static bool IsDisplayNameValid(string displayName)
        {
            if (StringHelper.IsNull(displayName))
            {
                throw ExceptionHelper.CreateArgumentNullException("displayName");
            }

            return (bool)MessengerEntity.Invoke(typeof(IMAddressPresence), "IsDisplayNameValid", displayName);
        }

        /// <summary>
        /// Determines whether the provided personal message is valid.
        /// </summary>
        /// <param name="message">The personal message to validate.</param>
        /// <returns><c>true</c> if the personal message is valid; <c>false</c> otherwise.</returns>
        public static bool IsPersonalMessageValid(string message)
        {
            if (StringHelper.IsNull(message))
            {
                throw ExceptionHelper.CreateArgumentNullException("message");
            }

            return (bool)MessengerEntity.Invoke(typeof(IMAddressPresence), "IsPersonalMessageValid", message);
        }

        private void OnPropertyChanged(object sender, MessengerEventArgs e)
        {
            this.OnPropertyChanged(
                new PropertyChangedEventArgs(
                    e.Entity.GetProperty<string>("PropertyName")));
        }

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, e);
            }
        }

        private void EnsureUser()
        {
            if (!this.address.IsUser)
            {
                throw new InvalidOperationException();
            }
        }
    }
}